package com.myk.game.gobangchess.rooms;

import com.myk.game.gobangchess.DataManager;
import com.myk.game.gobangchess.Mode;
import com.myk.game.gobangchess.Room;
import com.myk.game.gobangchess.Sign;
import com.myk.game.gobangchess.constants.BoardStyleData;
import com.myk.game.gobangchess.constants.ColorCost;
import com.myk.game.gobangchess.constants.WinMode;
import com.myk.game.gobangchess.signs.AroundSign;
import com.myk.game.gobangchess.signs.GroundSign;
import com.myk.game.gobangchess.signs.LineSign;
import com.myk.game.gobangchess.utils.GridsUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 通透五子棋房间
 */
public class YinYangTransparentGoBangRoom extends Room {

    private static final int[][] directions = {{1, 0}, {0, 1}, {1, 1}, {1, -1}};

    private static final int[][] kingMoves = {{-1, 1}, {-1, 0}, {-1, -1}, {0, 1}, {0, -1}, {1, -1}, {1, 0}, {1, 1}};

    private static final int EMPYTY_PIECE = 0;
    private static final int BLACK_PIECE = 1;
    private static final int WHITE_PIECE = 2;
    private static final int HALF_PIECCE = 8;
    public static final int WIN_SCORE = 30;
    private int initBlackScore = 0;
    private int initWhiteScore = 4;

    protected List<Sign> tempPointSigns = new ArrayList<>(); //记录最新落点的标记
    protected List<Sign> permanentPointSigns = new ArrayList<>(); //记录五连的标记
    private Point[][] points;

    private static final String MODE_120SEC = "步时120s";
    private static final String MODE_100SEC = "步时100s";
    private static final String MODE_90SEC = "步时90s";
    private static final String MODE_80SEC = "步时80s";
    private static final String MODE_60SEC = "步时60s";

    public YinYangTransparentGoBangRoom(String roomName) {
        super(roomName, "日出333设计的五子棋变体，黑白棋子可以落在同一个位置变成{{通子@scale=1.5}}，因此总是会产生令人意想不到的攻防效果！", "通透五子棋", BoardStyleData.getGoBangStyle(15, 15), true, true,MODE_60SEC,MODE_80SEC,MODE_90SEC,MODE_100SEC,MODE_120SEC);
    }

    @Override
    public int getCountdownSec() {
        if (Mode.isCurMode(this, MODE_60SEC)){
            return 60;
        }
        if (Mode.isCurMode(this, MODE_80SEC)){
            return 80;
        }
        if (Mode.isCurMode(this, MODE_90SEC)){
            return 90;
        }
        if (Mode.isCurMode(this, MODE_100SEC)){
            return 100;
        }
        if (Mode.isCurMode(this, MODE_120SEC)){
            return 120;
        }
        return super.getCountdownSec();
    }

    @Override
    public String getRuleText() {
        return "【基础规则】\n" +
                "15路棋盘，黑先白后，轮流落子。\n" +
                "每形成一个连五，得10分。达到30分为胜。\n" +
                "【特殊规则】\n" +
                "“通子”：既是黑子又是白子，属于双方共有。\n" +
                "我方走棋时，可以落子在敌子上，使之变成通子。同时，要付出代价：与该通子直线或斜线相连的我方棋子有N枚，则我方要扣2N分。\n" +
                "开局时，白棋自动获得4分，以弥补后手劣势。\n" +
                "终局时，若双方都没达到30分，则分多者胜。";
    }

    @Override
    protected void doStart() {
        blackScore = initBlackScore;
        whiteScore = initWhiteScore;
//        super.doStart();
        DataManager.noticeAllGameStart(player_black, player_white, roomName);
        overFlag = 1;//重置结束状态：对弈进行中未结束
        playingStartTime = System.currentTimeMillis(); //重置对弈开始时间
        resetGrids();
        noticeBlackMove();
        preHistory();
//        super.doStart();
        points = new Point[curGrids.length][curGrids[0].length];
        for (int i = 0; i < curGrids.length; i++) {
            for (int j = 0; j < curGrids[0].length; j++) {
                points[i][j] = new Point();
            }
        }
    }

    @Override
    public void doRule(int row, int col, int value) {
        boolean isTip = false;
        int thisPiece = curGrids[row][col];
        if (thisPiece == EMPYTY_PIECE) {
            curGrids[row][col] = cur;
        } else if (thisPiece == BLACK_PIECE) {
            if (cur == 2) {
                int countNum = countLine(GridsUtils.copyGrids(curGrids),row,col,value);
                curGrids[row][col] = HALF_PIECCE;
                whiteScore-=countNum*2;
                gameTip = "白方扣"+countNum*2+"分";
                isTip = true;
            } else
                return;
        } else if (thisPiece == WHITE_PIECE) {
            if (cur == 1) {
                int countNum = countLine(GridsUtils.copyGrids(curGrids),row,col,value);
                curGrids[row][col] = HALF_PIECCE;
                blackScore-=countNum*2;
                gameTip = "黑方扣"+countNum*2+"分";
                isTip = true;
            } else
                return;
        } else
            return;

        tempPointSigns.add(new GroundSign(getIndex(row, col), "#00000000", ColorCost.NEW_PUT_POINT, 1.0f, 0, 0));
        stepAdd();
        int addScore = checkLine();
        if (addScore != 0) {
            String text = cur == 1 ? "黑方" : "白方";
            if (!isTip)
                gameTip = text + "获得" + addScore + "分";
            else
                gameTip+="并获得" + addScore + "分";
        }
        changeMove();
    }

    @Override
    public String getGameInfo() {
        signList.clear();
        signList.addAll(tempPointSigns);
//        signList.addAll(permanentPointSigns);//注释本行取消连五线
        return super.getGameInfo();

    }

    public static int countLine(int[][] curGrids, int row, int col,int nowCur) {
        // 检查边界条件
        if (curGrids == null || row < 0 || row >= curGrids.length || col < 0 || col >= curGrids[0].length) {
            return 0;
        }



        // 定义相邻点的偏移量，包含横线、竖线和斜线
        int[][] directions = {
                {0, 1}, {0, -1}, {1, 0}, {-1, 0},   // 横线和竖线
                {-1, -1}, {-1, 1}, {1, -1}, {1, 1}  // 斜线
        };
        int countN = 0;

        // 使用深度优先搜索（DFS）遍历相连的直线
        for(int[] dir:directions){
            if (row+dir[0] >= 0 && row+dir[0] < curGrids.length && col+dir[1] >= 0 && col+dir[1] < curGrids[0].length )
                countN+=dfs(curGrids, row+dir[0], col+dir[1], dir,nowCur);
        }
        return countN;
    }

    private static int dfs(int[][] curGrids, int row, int col, int[] dir,int nowCur) {
        // 将当前点标记为已访问
        int temp = curGrids[row][col];
        curGrids[row][col] = -1;

        // 记录的数量
        int count = (temp == nowCur || temp == HALF_PIECCE) ? 1 : 0;
        if (count == 0) {
            return 0;
        }
        // 遍历相邻点

        int newRow = row + dir[0];
        int newCol = col + dir[1];

        // 检查相邻点是否在边界内，并且未被访问过
        if (newRow >= 0 && newRow < curGrids.length && newCol >= 0 && newCol < curGrids[0].length &&
                curGrids[newRow][newCol] != -1) {
            // 检查相邻点是否为
            if (curGrids[newRow][newCol] == nowCur || curGrids[newRow][newCol] == HALF_PIECCE) {
                count += dfs(curGrids, newRow, newCol, dir,nowCur);
            }
        }


        return count;
    }
    private void changeMove() {
        if (!checkWin()) {
            if (cur == 2) {
                noticeBlackMove();
            } else if (cur == 1) {
                noticeWhiteMove();
            }
        }
        gameTip = "";
        tempPointSigns = new ArrayList<>();
    }

    private boolean checkWin() {
        int blankNum = GridsUtils.getDataCount(curGrids, 0);  //没有胜负也没有空子了算战平
        if (blankNum == 0) {
            if (blackScore == whiteScore){
                doOver(WinMode.BOTH_DRAW, player_black.getNickNameOrTemp() + "-黑棋战平" + player_white.getNickNameOrTemp() + "-白棋");
                return true;
            } else if (blackScore>whiteScore) {
                doOver(WinMode.BLACK_WIN, player_black.getNickNameOrTemp() + "执黑棋战胜" + player_white.getNickNameOrTemp());
                return true;
            } else {
                doOver(WinMode.WHITE_WIN, player_white.getNickNameOrTemp() + "执白棋战胜" + player_black.getNickNameOrTemp());
                return true;
            }
        } else if (blackScore >= WIN_SCORE) {
            doOver(WinMode.BLACK_WIN, player_black.getNickNameOrTemp() + "执黑棋战胜" + player_white.getNickNameOrTemp());
            return true;
        } else if (whiteScore >= WIN_SCORE) {
            doOver(WinMode.WHITE_WIN, player_white.getNickNameOrTemp() + "执白棋战胜" + player_black.getNickNameOrTemp());
            return true;
        }
        return false;
    }

    public int checkLine() {
        int addScore = 0;
        List<int[]> winningPoints = new ArrayList<>();
        for (int i = 0; i < curGrids.length; i++) {
            for (int j = 0; j < curGrids[0].length; j++) {
                if (cur == 1) {
                    if (curGrids[i][j] == BLACK_PIECE || curGrids[i][j] == HALF_PIECCE) {
                        for (int k = 0; k < directions.length; k++) {
                            if ((points[i][j]).blackIsLine[k])
                                continue;
                            int[] direction = directions[k];
                            winningPoints = findWinningLine(curGrids, i, j, cur, k);
                            if (!winningPoints.isEmpty()) {
                                if (cur == 1) {
                                    for (int[] p : winningPoints) {
                                        Point pp = points[p[0]][p[1]];
                                        pp.blackIsLine[k] = true;
                                    }
                                }
                                blackScore+=10;
                                addScore+=10;
                            }
                        }
                    }
                } else if (cur == 2) {
                    if (curGrids[i][j] == WHITE_PIECE || curGrids[i][j] == HALF_PIECCE) {
                        for (int k = 0; k < directions.length; k++) {
                            if ((points[i][j]).whiteIsLine[k])
                                continue;
                            int[] direction = directions[k];
                            winningPoints = findWinningLine(curGrids, i, j, cur, k);
                            if (!winningPoints.isEmpty()) {
                                if (cur == 2) {
                                    for (int[] p : winningPoints) {
                                        Point pp = points[p[0]][p[1]];
                                        pp.whiteIsLine[k] = true;
                                    }
                                }
                                whiteScore+=10;
                                addScore+=10;
                            }
                        }
                    }
                }
            }
        }
        return addScore;
    }

    private List<int[]> findWinningLine(int[][] board, int x, int y, int player, int k) {
        int[] direction = directions[k];
        List<int[]> pointss = new ArrayList<>();
        int count = 0;
        int i = x;
        int j = y;

        while (i >= 0 && i < board.length && j >= 0 && j < board[0].length && (board[i][j] == player || board[i][j] == HALF_PIECCE)) {
            if (((points[i][j]).whiteIsLine[k] && cur == WHITE_PIECE) || ((points[i][j]).blackIsLine[k] && cur == BLACK_PIECE))
                return new ArrayList<>();
            pointss.add(new int[]{i, j});
            count++;
            i += direction[0];
            j += direction[1];
        }

        if (count >= 5) {
            permanentPointSigns.add(new LineSign(getIndex(pointss.get(0)[0],pointss.get(0)[1]),getIndex(pointss.get(count-1)[0],pointss.get(count-1)[1]),cur == 1?"#B2B2B2B2":"#B24C4C4C",0));
            return pointss;
        }

        return new ArrayList<>();
    }

    static class Point {
        boolean[] blackIsLine;//该位置黑子是否已经形成五连及以上,0为上下,1为左右,2为左上,3为右上
        boolean[] whiteIsLine;//该位置白子是否已经形成五连及以上,0为上下,1为左右,2为左上,3为右上

        public Point() {
            blackIsLine = new boolean[4];
            whiteIsLine = new boolean[4];
        }
    }

    @Override
    public void resetGrids() {
        tempPointSigns = new ArrayList<Sign>();
        permanentPointSigns = new ArrayList<Sign>();
        super.resetGrids();
    }
}
